# -*- coding: utf-8 -*-
'''
@文件    :base.py
@说明    :合利宝操作基础类
@时间    :2025/08/02 01:52:39
@作者    :浪晋
@版本    :1.0
'''

import requests
from typing import Dict
from .. import utils
from .. import config
from loguru import logger
import json


class BaseClient:
    def __init__(self,base_url=None, merchant_number=None, helipay_public_key=None, public_key=None, private_key=None):
        """
        初始化合利宝商户进件接口  
        :param merchant_number: 商户编号  
        :param helipay_public_key: 合利宝平台公钥  
        :param private_key: SM2私钥  
        :param public_key: SM2公钥  
        """
        self.base_url = base_url or config.base_url

        self.merchant_number = merchant_number or config.merchant_number
        self.helipay_public_key = helipay_public_key or config.helipay_public_key
        self.public_key = public_key or config.public_key
        self.private_key = private_key or config.private_key
        
        self.sm2 = utils.gm.SM2(public_key=self.public_key,private_key=self.private_key,helipay_public_key=self.helipay_public_key)
        self.sm4 = utils.gm.SM4()
        self.encryption_key = self.sm4.generate_key()


    def _sm4_encrypt(self, data):
        """SM4加密"""
        if not data:
            return ''
        return self.sm4.encrypt(self.encryption_key, data)

    def _sm4_decrypt(self, decrypt_key, data):
        """SM4解密"""
        if not data:
            return ''
        return self.sm4.decrypt(decrypt_key, data)


    def _build_merchant_data(self, interfaceName, body: Dict):
        """构建商户进件文档中的参数"""
        logger.info(f"原始body数据: {body}")
        data = {
            'interfaceName': interfaceName,
            "body":self._sm4_encrypt(body),
            "merchantNo": self.merchant_number,
            "signType": "SM3WITHSM2",  # SM3WITHSM2/MD5
            "encryptionKey": self.sm2.helipay_encrypt(self.encryption_key, True)
        }
        exclude_fields = ['interfaceName','signType','encryptionKey']
        filtered = {k: v for k, v in data.items() if k not in exclude_fields}
        sorted_params = utils.parameter.sort_dict_prefix_keys(filtered)
        sign_str = '&'.join([f"{v}" for _, v in sorted_params.items()])
        data['sign'] = self.sm2.generate_sign(sign_str)
        logger.info(f"构建data数据: {data}")
        return data


    def _build_common_data(self, interfaceName, body: Dict):
        """构建快捷支付/微信支付/账户余额查询文档中的参数"""
        logger.info(f"原始body数据: {body}")
        data = {
            'P1_bizType': interfaceName,
            "signatureType": "SM3WITHSM2",  # SM3WITHSM2/MD5
            "encryptionKey": self.sm2.helipay_encrypt(self.encryption_key, True)
        }
        data.update(body)
        exclude_fields = ['encryptionKey', 'signatureType', 'sign', 'dealSceneParams', 'dealSceneType', 'appName', 'appType', 'lbs', 'enrollTime', 'userAccount', 'goodsQuantity', 'sendValidateCode', 'protocolType', 'splitBillType', 'ruleJson']
        filtered = {k: v for k, v in data.items() if k not in exclude_fields}
        sorted_params = utils.parameter.sort_dict_prefix_keys(filtered)
        sign_str = '&' + '&'.join([f"{v}" for _, v in sorted_params.items()])
        data['sign'] = self.sm2.generate_sign(sign_str)
        logger.info(f"构建data数据: {data}")
        return data


    def _build_delayedSplit_data(self, merchantNo, body: Dict):
        """构建延时分帐文档中的参数"""
        logger.info(f"原始请求数据: {body}")
        data = {
            "data":self._sm4_encrypt(body),
            "customerNumber": merchantNo,
            "timestamp": utils.parameter.generate_timestamp(),
            "version": "1.0",
            "signType": "SM3WITHSM2",  # SM3WITHSM2/MD5
            "encryptionKey": self.sm2.helipay_encrypt(self.encryption_key, True)
        }
        data['sign'] = self.sm2.generate_sign(data['data'])
        logger.info(f"加密请求数据: {data}")
        return data


    def _build_transfer_data(self, interfaceName, body: Dict):
        """构建结算文档中的参数"""
        logger.info(f"原始请求数据: {body}")
        data = {
            'P1_bizType': interfaceName,
            "signType": "SM3WITHSM2"  # SM3WITHSM2/MD5
        }
        data.update(body)
        exclude_fields = ['encryptionKey', 'sign', 'P6_notifyUrl']
        filtered = {k: v for k, v in data.items() if k not in exclude_fields}
        sorted_params = utils.parameter.sort_dict_prefix_keys(filtered)
        sign_str = '&' + '&'.join([f"{v}" for _, v in sorted_params.items()])
        logger.info(f"待签名字符串: {sign_str}")
        data['sign'] = self.sm2.generate_sign(sign_str)
        logger.info(f"加密请求数据: {data}")
        return data


    def _build_decrypt_result(self, result: Dict):
        """构建解密结果"""
        if result.get("success", False) is False or result["code"] != "0000":
            return result
        decrypt_key = self.sm2.decrypt(result["encryptionKey"])
        data = self._sm4_decrypt(decrypt_key, result["data"])
        result["data"] = json.loads(data)
        logger.info(f"解密响应结果: {result}")
        return result


    def _build_sign_result(self, result: Dict):
        """构建签名对比结果"""
        if result["rt2_retCode"] != "0000":
            return result
        exclude_fields = ['encryptionKey', 'signatureType', 'sign', 'rt13_d1Balance', 'rt14_rechargeBalance', 'rt15_amountToBeSettled', 'rt16_splittableAmount']
        filtered = {k: v for k, v in result.items() if k not in exclude_fields}
        sorted_params = utils.parameter.sort_dict_prefix_keys(filtered, "rt")
        logger.info(f"排序后需要签名的字段: {sorted_params}")
        sign_str = '&' + '&'.join([f"{v}" for _, v in sorted_params.items()])
        logger.info(f"待签名字符串: {sign_str}")
        sign = self.sm2.generate_sign(sign_str)
        logger.info(f"sign1:  {sign}")
        logger.info(f"sign2:  {result['sign']}")
        # assert result['sign'] == sign
        logger.info(f"响应校验结果: {result}")
        return result


    def _request(self, url, headers, data, verified="decrypt"):
        """请求通用方法"""
        if "json" in headers["Content-Type"]:
            data = json.dumps(data)
        response = requests.request("POST", url, headers=headers, data=data)
        logger.info(f"原始响应结果: {response.text}")
        result = response.json()
        if verified == "decrypt":
            result = self._build_decrypt_result(result)
        else:
            result = self._build_sign_result(result)
        return result


    def demo(self, merchantNo, callBackUrl):
        """获取电子合同签约url"""
        url = self.base_url + "/trx/merchantEntry/interface.action"
        headers = {
            "Content-Type":"application/x-www-form-urlencoded;charset=utf-8"
        }
        body = {
            "merchantNo":self.merchant_number,
            "emerchantNo": merchantNo,
            "callBackUrl": callBackUrl
        }
        data = self._build_merchant_params('getSignContractUrl', body)
        return self._request(url, headers=headers, data=data)



